/**
 * Created by Mr.chen on 2020.
 **/
import axios from 'axios';
import router from '@/router'

// 一个可以将json转化为 x1='aa'&x1='bb' 字符串的好工具
import qs from 'qs';

// 工具类
import md5 from 'js-md5';
import { setStore, getStore } from '@/utils/util';
import { TOKEN } from '@/utils/const';

// ====================== 创建axios实例 ======================
// 配置请求头
// axios.defaults.withCredentials = true;
// axios.defaults.headers.common['Authorization'] = AUTH_TOKEN;
// axios.defaults.headers.post['Content-Type'] = 'application/x-www-form-urlencoded';

// 配置当前axios实例配置项
const BASE_OPTIONS = {
  // 开发环境与生产环境区分
  baseURL: process.env.BASE_URL,
  // 一般超时时间设置 20s~30s 之间
  timeout: 25000,
  // TODO: 加了之后我不知道为啥报错 跨域允许携带凭证
  // withCredentials: true,
  // 设置参数请求格式: ?x1='x11'&x2='x22'
  // headers: {
  //   'Content-Type': 'application/x-www-from-urlencoded'
  // },
  // 只针对POST请求参数的处理 GET则获取不到
  // transformRequest: data => {
  //   const res = qs.stringify(data);
  //   console.log("我接收到的数据 =>", data);
  //   console.log("我处理下 =>", res);
  //   return res;
  // },
  // 自定义响应成功的HTTP状态码
  // validateStatus: status => {
  //   // 2 或 3 开头的状态码算成功
  //   return /^(2|3))\d{2}$/.test(status);
  // }
}
const instance = axios.create(BASE_OPTIONS);

// const platform = "Web";
// const signType = "MD5";
// const timestamp = +new Date();
// const version = "v1.0";


// ====================== 拦截器 ======================
// 请求拦截器
instance.interceptors.request.use(
  config => {
    const token = getStore(TOKEN) || "none";
    // 将token夹杂在headers中给到后台
    config.headers['Token'] = token;
    // console.group("请求拦截器 =>");
    // console.log("你要的token >>>", token, " type >>>", typeof token);
    // console.groupEnd();
    return config;
  },
  error => {
    // Do something with request error
    return Promise.reject(error);
  });

// 响应拦截器
instance.interceptors.response.use(
  response => {
    // 判断token是否失效
    if (response.data) {
      if (parseInt(response.data.code) === 4001) {
        // 用户已在别处登录 或者 token已过期 回到登录页面重新登录
        setStore(TOKEN, '')
        router.push({ path: '/' })
      }
    }
    // data: {} 响应主体内容
    return response.data;
  },
  error => {
    let { response } = error;
    if (response) {
      // => 收到服务器返回结果
      let message = "";
      switch (response.status) {
        case 400: // 传递参数错误
          message = "参数有误";
          console.log("400 请检查传递的参数是否有误");
          break;
        case 401: // 用户未登录 => 一般是权限
          break;
        case 403: // 服务器已拒绝 => token过期
          break;
        case 404: // 找不到页面
          break;
      }
      return Promise.reject(message);
    } else {
      // => 未收到服务器返回结果 [客户端断网、服务端挂了]
      if (!window.navigator.onLine) {
        // 断网处理 => 可以跳转到断网页面
        return;
      } else {
        // 服务端挂了...
        return Promise.reject(error);
      }
    }

  }
);


/**
 * @method 后端约束签名参数
 * @param {String} platform       公共参数：平台： Web、PC、Android、iOS 等
 * @param {String} sign           公共参数：参数排序后获得的MD5值
 * @param {String} signType       公共参数：签名校验类型： MD5
 * @param {String} timestamp      公共参数：13 位时间戳（ms）
 * @param {String} version        公共参数：版本： v1.0
 * @param {String} salt           公共参数：盐 直接拼接到最后的参数字符串上即可
 */
const salt = "publicSchool_V1.0"
const PUBLIC_SIGN = {
  platform: "Web",
  signType: "MD5",
  timestamp: +new Date() + "",
  version: "v1.0"
}

// 加密传输参数通用方法封装
function encryptionParams(data = {}) {
  // md5加密参数列表
  let md5List = [];

  // 将请求参数与公共参数合并到一个对象中
  Object.keys(PUBLIC_SIGN).forEach(item => data[item] = PUBLIC_SIGN[item])

  // 根据对象中的key进行排序「a-z」
  // 参数value为空不进入加密
  Object.keys(data).sort().filter((item) => {
    // JS中 "" == 0 所以先判断类型
    if (typeof data[item] == "string" && data[item] == "") {
      console.log(`${item} 不进入加密`);
    } else {
      md5List.push(`${item}=${data[item]}&`)
    }
  })

  // 加盐
  md5List.push(salt);

  // 加上签名参数进行请求
  data["sign"] = md5(md5List.join(""));

  // 返回处理后的对象数据
  return data;
}


// 几种通用请求方式封装 GET、POST、PUT、DELETE
/**
 * @method GET请求
 * @param {String} URL      请求地址
 * @param {Object} params   url传递参数, 拼接在url之后
 */
export const GET = (URL, params) => instance.get(URL, { params: encryptionParams(params) });

/**
 * @method POST请求
 * @param {String} URL      请求地址
 * @param {Object} data     body传递参数
 * @param {Object} params   url传递参数, 拼接在url之后
 */
export const POST = (URL, data, params) => instance.post(`${URL}`, encryptionParams(data), { params });

/**
 * @method PUT请求
 * @param {String} URL      请求地址
 * @param {Object} data     body传递参数
 * @param {Object} params   url传递参数, 拼接在url之后
 */
export const PUT = (URL, data, params) => instance.put(URL, encryptionParams(data), { params });

/**
 * @method DELETE请求
 * @param {String} URL      请求地址
 * @param {Object} data     body传递参数
 * @param {Object} params   url传递参数, 拼接在url之后
 */
export const DELETE = (URL, data, params) => instance.delete(URL, { data: encryptionParams(data), params });

// * PATCH
export const PATCH = (URL, params) => instance.patch(URL, params);


// ====================== 导出让外部使用 ======================
// 导出当前axios实例对象 [默认]
export default instance;
